﻿// ============================================================================
//  _ __   ___  ___  ___ _ __ ___  _   _
// | '_ \ / _ \/ __|/ _ \ '_ ` _ \| | | |
// | | | |  __/\__ \  __/ | | | | | |_| |
// |_| |_|\___||___/\___|_| |_| |_|\__,_|
//
// NES Emulator by daxnet, 2024
// MIT License
// ============================================================================

namespace NesEmu.Core;

/// <summary>
///     Represents the addressing modes.
/// </summary>
/// <remarks>The documentation is based on https://www.nesdev.org/obelisk-6502-guide/addressing.html.</remarks>
public enum AddressingMode
{
    /// <summary>
    ///     The source and destination of the information to be manipulated is implied directly
    ///     by the function of the instruction itself and no further operand needs to be specified.
    ///     For example, operations like "Clear Carry flag" (CLC) and "Return from subroutine" are
    ///     implicit.
    /// </summary>
    Implicit,

    /// <summary>
    ///     Some instructions have an option to operate directly upon the accumulator. For example:
    ///     "LSR A" and "ROR A" instructions.
    /// </summary>
    Accumulator,

    /// <summary>
    ///     An 8 bit constant is specified directly as the operand of the instruction. It is indicated
    ///     by a '#' symbol followed by an numeric expression. For example: "LDA #10".
    /// </summary>
    Immediate,

    /// <summary>
    ///     An instruction using zero page addressing mode has only an 8 bit address operand. This limits
    ///     it to addressing only the first 256 bytes of memory (e.g. $0000 to $00FF) where the most significant
    ///     byte of the address is always zero. In zero page mode only the least significant byte of the address
    ///     is held in the instruction making it shorter by one byte (important for space saving) and one less
    ///     memory fetch during execution (important for speed). An assembler will automatically select zero page
    ///     addressing mode if the operand evaluates to a zero page address and the instruction supports the mode (not all do).
    /// </summary>
    ZeroPage,

    /// <summary>
    ///     The addressing is calculated by taking the 8 bit zero page address from the instruction and adding
    ///     the current value of the X register to it. For example, if the X register contains 0xf and the instruction
    ///     "LDA $80,X" is executed then the accumulator will be loaded from 0x8f (which is 0x80 + 0xf). Note that
    ///     the address calculation wraps around if the sum of the base address and the register exceeds 0xff. In the
    ///     above example, if the value in the X register is 0xff, then the calculated addressing will be 0x7f, which
    ///     is (0x80 + 0xff) & 0xff.
    /// </summary>
    ZeroPageX,

    /// <summary>
    ///     The addressing is calculated by taking the 8 bit zero page address from the instruction and adding
    ///     the current value of Y register to it. This mode can only be used with the LDX and STX instructions.
    /// </summary>
    ZeroPageY,

    /// <summary>
    ///     This addresing mode is used by branch instructions (e.g. BEQ, BNE, etc.) which contain a signed 8 bit relative
    ///     offset (ranging from -128 to 127) which is added to the program counter (PC) if the condition is true. As the
    ///     program counter itself is increased during instruction execution by two, the effective address range for the
    ///     target instruction must be with -126 to 129 bytes of the branch.
    /// </summary>
    Relative,

    /// <summary>
    ///     Absolute addressing contains a full 16 bit address to identify the target location.
    /// </summary>
    Absolute,

    /// <summary>
    ///     The address to be accessed by an instruction using X register indexed absolute addressing is computed by taking
    ///     the 16 bit address from the instruction and added the contents of the X register. For example, if X contains 0x92
    ///     then an "STA $2000,X" instruction will store the accumulator at $2092 (e.g. $2000 + $92).
    /// </summary>
    AbsoluteX,

    /// <summary>
    ///     The address to be accessed by an instruction using Y register indexed absolute addressing is computed by taking
    ///     the 16 bit address from the instruction and added the contents of the Y register. For example, if Y contains 0x92
    ///     then an "STA $2000,Y" instruction will store the accumulator at $2092 (e.g. $2000 + $92).
    /// </summary>
    AbsoluteY,

    /// <summary>
    ///     JMP is the only 6502 instruction to support indirection. The instruction contains a 16 bit address which identifies
    ///     the location of the least significant byte of another 16 bit memory address which is the real target of the
    ///     instruction.
    ///     For example if location $0120 contains $FC and location $0121 contains $BA then the instruction JMP ($0120) will
    ///     cause the
    ///     next instruction execution to occur at $BAFC (e.g. the contents of $0120 and $0121).
    /// </summary>
    Indirect,

    /// <summary>
    ///     Indexed indirect addressing is normally used in conjunction with a table of address held on zero page.
    ///     The address of the table is taken from the instruction and the X register added to it (with zero page wrap around)
    ///     to give
    ///     the location of the least significant byte of the target address. (a.k.a Indirect.X).
    /// </summary>
    IndexedIndirect,

    /// <summary>
    ///     Indirect indirect addressing is the most common indirection mode used on the 6502. In instruction contains the zero
    ///     page
    ///     location of the least significant byte of 16 bit address. The Y register is dynamically added to this value to
    ///     generated
    ///     the actual target address for operation. (a.k.a Indirect.Y).
    /// </summary>
    IndirectIndexed
}